using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Security;
using IWS.Lib.SingleSignOn.MembershipWebService;


namespace IWS.Lib.SingleSignOn
{
	/// <summary>
	/// The web service membership provider 
	/// </summary>
	public class WebServiceMembershipProvider : MembershipProvider
	{
		private string sServiceKey;
		private string sUrl;
			
		public WebServiceMembershipProvider()
		{
			this.sServiceKey = String.Empty;
		}


		IWS.Lib.SingleSignOn.MembershipWebService.MembershipService GetServiceInstance()
		{
			MembershipService svc = new MembershipService();
			svc.Url = sUrl.TrimEnd(new char[] { '/' }) + "/MembershipService.asmx";
			return svc;
		}

		/// <summary>
		/// Initialize the provider. 
		/// </summary>
		/// <remarks>Part of the initialization process includes establishing a session with the remote provider for security.</remarks>
		/// <param name="name"></param>
		/// <param name="config"></param>
		public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
		{
			base.Initialize(name, config);
			//read key. 
			string mode = this.GetConfigValue(config["ServiceMode"], "Static");
			string url = this.GetConfigValue(config["ServiceUrl"], string.Empty);
			if (string.IsNullOrEmpty(url))
				throw new ArgumentNullException("Missing ServiceUrl key in membership provider configuration.");

			this.sUrl = url;

			if (mode.ToUpper().Trim() == "STATIC")
			{
				SecurityContext.Mode = WebServiceSecurityMode.Static;
				string service_key_file = this.GetConfigValue(config["ServiceKeyFile"], "~/sso.xkey");
				SecurityContext.CurrentKey = IWS.Lib.SingleSignOn.MediumTrustSecurity.ReadKeyFile(IWS.Lib.SingleSignOn.MediumTrustSecurity.ResolveKeyFile(service_key_file));
				this.sServiceKey = SecurityContext.CurrentKey;
			}
			else if (mode.ToUpper().Trim() == "DYNAMIC")
				SecurityContext.Mode = WebServiceSecurityMode.Dynamic;
		}

		private string GetConfigValue(string configValue, string defaultValue)
		{
			if (String.IsNullOrEmpty(configValue))
				return defaultValue;

			return configValue;
		}


		public override string ApplicationName
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetApplicationName(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					return resp.Data.ToString();
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
			set
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.SetApplicationName(this.sServiceKey, value);
				if (resp.Result != eResult.Success)
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override bool ChangePassword(string username, string oldPassword, string newPassword)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.ChangePassword(this.sServiceKey, username, oldPassword, newPassword);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.ChangePasswordQuestionAndAnswer(this.sServiceKey, username, password, newPasswordQuestion, newPasswordAnswer);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override System.Web.Security.MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out System.Web.Security.MembershipCreateStatus status)
		{
			MembershipService svc = GetServiceInstance();
			
			CreateUserServiceResponse resp = svc.CreateUser(this.sServiceKey, username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey);
			if (resp.Result == eResult.Success)
			{
				CreateUserResult result = resp.Data as CreateUserResult;
				if (result != null)
				{
					status = (System.Web.Security.MembershipCreateStatus)result.CreateStatus;
					return ProxyTranslator.GetMembershipUser(result.User);
				}
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool DeleteUser(string username, bool deleteAllRelatedData)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.DeleteUser(this.sServiceKey, username, deleteAllRelatedData);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool EnablePasswordReset
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetEnablePasswordReset(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (bool)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override bool EnablePasswordRetrieval
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetEnablePasswordRetrieval(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (bool)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			MembershipService svc = GetServiceInstance();
			UserCollectionServiceResponse resp = svc.FindUsersByEmail1(this.sServiceKey, emailToMatch, pageIndex, pageSize);
			if (resp.Result == eResult.Success)
			{
				UserCollectionResult result = resp.Data as UserCollectionResult;
				if (result != null)
				{
					totalRecords = result.TotalRecords;
					return ProxyTranslator.GetUserCollection(result.MatchingUsers);
				}
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			MembershipService svc = GetServiceInstance();
			UserCollectionServiceResponse resp = svc.FindUsersByName1(this.sServiceKey, usernameToMatch, pageIndex, pageSize);
			if (resp.Result == eResult.Success)
			{
				UserCollectionResult result = resp.Data as UserCollectionResult;
				if (result != null)
				{
					totalRecords = result.TotalRecords;
					return ProxyTranslator.GetUserCollection(result.MatchingUsers);
				}
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
		{
			MembershipService svc = GetServiceInstance();
			UserCollectionServiceResponse resp = svc.GetAllUsers1(this.sServiceKey, pageIndex, pageSize);
			if (resp.Result == eResult.Success)
			{
				UserCollectionResult result = resp.Data as UserCollectionResult;
				if (result != null)
				{
					totalRecords = result.TotalRecords;
					return ProxyTranslator.GetUserCollection(result.MatchingUsers);
				}
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override int GetNumberOfUsersOnline()
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.GetNumberOfUsersOnline(this.sServiceKey);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return (int)resp.Data;
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override string GetPassword(string username, string answer)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.GetNumberOfUsersOnline(this.sServiceKey);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return resp.Data.ToString();
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override System.Web.Security.MembershipUser GetUser(string username, bool userIsOnline)
		{
			MembershipService svc = GetServiceInstance();
			MembershipUserServiceResponse resp = svc.GetUser2(this.sServiceKey, username, userIsOnline);
			if (resp.Result == eResult.Success)
			{
				MembershipUserProxy user = resp.Data as MembershipUserProxy;
				if (user != null)
					return ProxyTranslator.GetMembershipUser(user);
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override System.Web.Security.MembershipUser GetUser(object providerUserKey, bool userIsOnline)
		{
			MembershipService svc = GetServiceInstance();
			MembershipUserServiceResponse resp = svc.GetUser4(this.sServiceKey, providerUserKey, userIsOnline);
			if (resp.Result == eResult.Success)
			{
				MembershipUserProxy user = resp.Data as MembershipUserProxy;
				if (user != null)
					return ProxyTranslator.GetMembershipUser(user);
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override string GetUserNameByEmail(string email)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.GetUserNameByEmail(this.sServiceKey, email);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return resp.Data.ToString();
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override int MaxInvalidPasswordAttempts
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetMaxInvalidPasswordAttempts(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (int)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override int MinRequiredNonAlphanumericCharacters
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetMinRequiredNonAlphanumericCharacters(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (int)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override int MinRequiredPasswordLength
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetMinRequiredPasswordLength(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (int)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override int PasswordAttemptWindow
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetPasswordAttemptWindow(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (int)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override MembershipPasswordFormat PasswordFormat
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.PasswordFormat(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (MembershipPasswordFormat)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override string PasswordStrengthRegularExpression
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetPasswordStrengthRegularExpression(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return resp.Data.ToString();
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override bool RequiresQuestionAndAnswer
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetRequiresQuestionAndAnswer(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (bool)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override bool RequiresUniqueEmail
		{
			get
			{
				MembershipService svc = GetServiceInstance();
				ServiceResponse resp = svc.GetRequiresUniqueEmail(this.sServiceKey);
				if (resp.Result == eResult.Success)
				{
					if (resp.Data != null)
						return (bool)resp.Data;
					else
						throw new ServiceException("Response contains no data.");
				}
				else
					throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override string ResetPassword(string username, string answer)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.ResetPassword(this.sServiceKey, username, answer);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return resp.Data.ToString();
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool UnlockUser(string userName)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.UnlockUser(this.sServiceKey, userName);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override void UpdateUser(System.Web.Security.MembershipUser user)
		{
			//TODO: replace this with a user proxy.
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.UpdateUser(this.sServiceKey, ProxyTranslator.GetUserProxy(user));
			if (resp.Result != eResult.Success)
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool ValidateUser(string username, string password)
		{
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.ValidateUser(this.sServiceKey, username, password);
			if (resp.Result == eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new ServiceException("Response contains no data.");
			}
			else
				throw new ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public bool GenerateSession(string username, string password)
		{
			//generate server key, kick it back to local memory, and perform login as normal. 
			MembershipService svc = GetServiceInstance();
			ServiceResponse resp = svc.GenerateSession(username, password);
			if (resp.Result == eResult.Success)
			{
				SecurityContext.CurrentKey = resp.Data.ToString();
				return true;
			}
			else if (resp.Result == eResult.InvalidRegistration)
				return false;
			else
				throw new ServiceException(resp.Message);
		}

		public void ExpireKey()
		{
			if (!string.IsNullOrEmpty(this.sServiceKey))
			{
				MembershipWebService.MembershipService svc = this.GetServiceInstance();
				svc.ExpireSession(this.sServiceKey);
				SecurityContext.CurrentKey = null;
			}
		}

	}
}
